/** @jsx jsx */
import React, { Fragment } from 'react';
import { jsx } from '@emotion/react';
import Helmet from 'react-helmet';
import md from '../../markdown/renderer';
import ExampleWrapper from '../../ExampleWrapper';
import {
  StyledSingle,
  StyledMulti,
  Theme,
  StyleCompositionExample,
} from '../../examples';
import { ColorSample } from '../../styled-components';
import { defaultTheme } from 'react-select';

export default function Styles() {
  return (
    <Fragment>
      <Helmet>
        <title>Styles - React Select</title>
        <meta
          name="description"
          content="React-Select offers a flexible, light-weight styling framework which is a thin abstraction over simple javascript objects"
        />
      </Helmet>
      {md`
    # Styles

    React-Select offers a flexible, light-weight styling framework which is
    a thin abstraction over simple javascript objects using
    [emotion](https://emotion.sh/).

    ~~~jsx
    /**
     * @param {Object} provided -- the component's default styles
     * @param {Object} state -- the component's current state e.g. \`isFocused\`
     * @returns {Object}
     */
    function styleFn(provided, state) {
      return { ...provided, color: state.isFocused ? 'blue' : 'red' };
    }
    ~~~

    ## Style Object

    Each component is keyed, and ships with default styles. The component's
    default style object is passed as the first argument to the function
    when it's resolved.

    The second argument is the current state of the select, features like
    \`isFocused\`, \`isSelected\` etc. allowing you to
    implement dynamic styles for each of the components.

    ###### Style Keys

    - \`clearIndicator\`
    - \`container\`
    - \`control\`
    - \`dropdownIndicator\`
    - \`group\`
    - \`groupHeading\`
    - \`indicatorsContainer\`
    - \`indicatorSeparator\`
    - \`input\`
    - \`loadingIndicator\`
    - \`loadingMessage\`
    - \`menu\`
    - \`menuList\`
    - \`menuPortal\`
    - \`multiValue\`
    - \`multiValueLabel\`
    - \`multiValueRemove\`
    - \`noOptionsMessage\`
    - \`option\`
    - \`placeholder\`
    - \`singleValue\`
    - \`valueContainer\`

    ## Provided Styles and State

    Spreading the provided styles into your returned object lets you extend it
    however you like while maintaining existing styles. Alternatively, you
    can omit the provided styles and completely take control of the component's styles.

    ~~~jsx
    const customStyles = {
      option: (provided, state) => ({
        ...provided,
        borderBottom: '1px dotted pink',
        color: state.isSelected ? 'red' : 'blue',
        padding: 20,
      }),
      control: () => ({
        // none of react-select's styles are passed to <Control />
        width: 200,
      }),
      singleValue: (provided, state) => {
        const opacity = state.isDisabled ? 0.5 : 1;
        const transition = 'opacity 300ms';

        return { ...provided, opacity, transition };
      }
    }

      const App = () => (
        <Select
          styles={customStyles}
          options={...}
        />
      );
      ~~~


    ## Select Props
    In the second argument \`state\`, you have access to \`selectProps\` which will allow you to gain access to
    your own arguments passed into the \`Select\` body.

    ~~~jsx
    const customStyles = {
      menu: (provided, state) => ({
        ...provided,
        width: state.selectProps.width,
        borderBottom: '1px dotted pink',
        color: state.selectProps.menuColor,
        padding: 20,
      }),

      control: (_, { selectProps: { width }}) => ({
        width: width
      }),

      singleValue: (provided, state) => {
        const opacity = state.isDisabled ? 0.5 : 1;
        const transition = 'opacity 300ms';

        return { ...provided, opacity, transition };
      }
    }

      const App = () => (
        <Select
          styles={customStyles}
          width='200px'
          menuColor='red'
          options={...}
        />
      );
      ~~~

      ${(
        <ExampleWrapper
          label="Customised Styles for Single Select"
          urlPath="docs/examples/StyledSingle.tsx"
          raw={require('!!raw-loader!../../examples/StyledSingle.tsx')}
        >
          <StyledSingle />
        </ExampleWrapper>
      )}

      ${(
        <ExampleWrapper
          label="Customised styles for Multi Select"
          urlPath="docs/examples/StyledMulti.tsx"
          raw={require('!!raw-loader!../../examples/StyledMulti.tsx')}
        >
          <StyledMulti />
        </ExampleWrapper>
      )}

    ## cx and custom Components

    In the event that you need to rewrite a particular component, you'll also have to compose together the styling functionality.
    Thankfully all the requisite parts are supplied to you via props as below:

    ### cx
    cx is an internal utility function that manages the composition of emotion style declarations, className/classNamePrefixes and
    additional BEM style modifiers into a selector value for each component.
    It has the following signature:

    ~~~
    (prefix ?: string,
      cssKey?: string,
      state?: {},
      className?: string) => string
    ~~~

    * prefix: is the value of the optional classNamePrefix,
    * cssKey: is the uid generated by the invocation of the css method imported from emotion
    * state: an object declaring state based modifiers to be applied to our selector
    * className: any className prop specified for custom components will also be composed into the selector string produced by the cx functions

    ### getStyles
    Each component gets passed a getStyles method which has the following signature:

    ~~~
    (key: string, props: Object) => stylesObject;
    ~~~

    The key is a lowercased string value corresponding to the component that the styles apply to,
    i.e. option for the Option component, menuplacer for the MenuPlacer component.

    The props argument is an object of relevant properties/ state values that are relevant to computing styles,
    i.e. isFocused or isSelected. Additional props can be added here for computation using the styles api.

    In the end configuring your custom component with the correct styling functionality should look like this
    ~~~
    import { css } from 'emotion';

    const CustomOption = ({ cx, children, getStyles, innerRef, ...props }) => (
      <div
        ref={innerRef}
        className={cx(
          css(getStyles('option', props)),
          {
            'option': true,
            'option--is-disabled': isDisabled,
            'option--is-focused': isFocused,
            'option--is-selected': isSelected,
          }
        )}
      >
        {children}
      </div>
    )
    ~~~

    ${(
      <ExampleWrapper
        label="Style composition for custom components"
        urlPath="docs/examples/StyleCompositionExample.tsx"
        raw={require('!!raw-loader!../../examples/StyleCompositionExample.tsx')}
      >
        <StyleCompositionExample />
      </ExampleWrapper>
    )}

    ## Using classNames

    If you provide the \`className\` prop to react-select, the SelectContainer will be given a className based on the provided value.

    If you provide the \`classNamePrefix\` prop to react-select, all inner elements will be given a className
    with the provided prefix.

    For example, given \`className='react-select-container'\` and \`classNamePrefix="react-select"\`,
    the DOM structure is similar to this:

    ~~~html
    <div class="react-select-container">
      <div class="react-select__control">
        <div class="react-select__value-container">...</div>
        <div class="react-select__indicators">...</div>
      </div>
      <div class="react-select__menu">
        <div class="react-select__menu-list">
          <div class="react-select__option">...</div>
        </div>
      </div>
    </div>
    ~~~

    While we encourage you to use the new Styles API, you still have the option of styling via CSS classes.
    This ensures compatibility with [styled components](https://www.styled-components.com/),
    [CSS modules](https://github.com/css-modules/css-modules) and other libraries.

    ## Overriding the theme

    The default styles are derived from a theme object, which you can mutate like \`styles\`.

    The \`theme\` object is available for the \`styles\` functions as well.

    ${(
      <ExampleWrapper
        label="Customised theme"
        urlPath="docs/examples/Theme.tsx"
        raw={require('!!raw-loader!../../examples/Theme.tsx')}
      >
        <Theme />
      </ExampleWrapper>
    )}

    ###### Theme colors

    ${(
      <div css={{ marginTop: '1em' }}>
        {Object.keys(defaultTheme.colors).map((key) => (
          <ColorSample
            key={key}
            name={key}
            color={defaultTheme.colors[key as keyof typeof defaultTheme.colors]}
          />
        ))}
      </div>
    )}

    `}
    </Fragment>
  );
}
